/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef THRIFT_UTIL_BITWISECAST_H_
#define THRIFT_UTIL_BITWISECAST_H_

// Use this to get around strict aliasing rules.
// For example, uint64_t i = bitwise_cast<uint64_t>(returns_double());
// The most obvious implementation is to just cast a pointer,
// but that doesn't work.
// For a pretty in-depth explanation of the problem, see
// http://cellperformance.beyond3d.com/articles/2006/06/ (...)
// understanding-strict-aliasing.html
template <typename To, typename From>
static inline To bitwise_cast(From from) {
  static_assert(sizeof(From) == sizeof(To), "");

  // BAD!!!  These are all broken with -O2.
  // return *reinterpret_cast<To*>(&from);  // BAD!!!
  // return *static_cast<To*>(static_cast<void*>(&from));  // BAD!!!
  // return *(To*)(void*)&from;  // BAD!!!

  // Super clean and partially blessed by section 3.9 of the standard.
  // unsigned char c[sizeof(from)];
  // memcpy(c, &from, sizeof(from));
  // To to;
  // memcpy(&to, c, sizeof(c));
  // return to;

  // Slightly more questionable.
  // Same code emitted by GCC.
  // To to;
  // memcpy(&to, &from, sizeof(from));
  // return to;

  // Technically undefined, but almost universally supported,
  // and the most efficient implementation.
  union {
    From f;
    To t;
  } u;
  u.f = from;
  return u.t;
}

#endif
